#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Odoo JSON-RPC Client - Read Hostel Students (改进版)
从 Odoo 服务器读取 hostel.student 模型的数据
"""

import json
import urllib.request
import urllib.parse
import ssl
import sys

# Odoo 服务器配置
ODOO_URL = "https://naturedao.tech/odoo"
API_KEY = "298a4b1128cb1bdb8da2bb87e0e9c11e9b82850f"

# 常见的数据库名称
COMMON_DB_NAMES = ["odoo", "odoodb", "postgres", "db", "odoo18", "odoo17", "production"]

# 创建忽略 SSL 验证的上下文
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE


def json_rpc(url, method, params):
    """执行 JSON-RPC 调用"""
    data = {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "id": 1,
    }
    
    req = urllib.request.Request(
        url=url,
        data=json.dumps(data).encode('utf-8'),
        headers={"Content-Type": "application/json"},
    )
    
    try:
        response = urllib.request.urlopen(req, context=ssl_context)
        result = json.loads(response.read().decode('utf-8'))
        
        if 'error' in result:
            return None, result['error']
        
        return result.get('result'), None
    
    except Exception as e:
        return None, str(e)


def list_databases():
    """获取数据库列表"""
    print("正在获取数据库列表...")
    
    result, error = json_rpc(
        f"{ODOO_URL}/jsonrpc",
        "call",
        {
            "service": "db",
            "method": "list",
            "args": []
        }
    )
    
    if result:
        return result
    else:
        # 如果无法获取数据库列表，返回常见数据库名
        print(f"  无法自动获取数据库列表，将尝试常见数据库名")
        return COMMON_DB_NAMES


def authenticate(database):
    """使用 API Key 进行身份验证"""
    result, error = json_rpc(
        f"{ODOO_URL}/jsonrpc",
        "call",
        {
            "service": "common",
            "method": "authenticate",
            "args": [database, "admin", API_KEY, {}]
        }
    )
    
    if result:
        return result, None
    else:
        return None, error


def search_read_students(database, uid, password):
    """读取 hostel.student 模型的数据"""
    fields = [
        'id', 'name', 'gender', 'class_id', 'room_id', 'hostel_id',
        'check_in_date', 'check_out_date', 'stay_duration', 'status', 'active',
    ]
    
    result, error = json_rpc(
        f"{ODOO_URL}/jsonrpc",
        "call",
        {
            "service": "object",
            "method": "execute_kw",
            "args": [
                database, uid, password,
                "hostel.student", "search_read",
                [],
                {
                    "fields": fields,
                    "limit": 100,
                    "order": "id desc",
                }
            ]
        }
    )
    
    return result, error


def print_students(students):
    """格式化打印学生数据"""
    if not students:
        print("\n没有找到任何学生记录。")
        return
    
    print(f"\n找到 {len(students)} 条学生记录：")
    print("=" * 120)
    
    header = f"{'ID':<6} {'姓名':<15} {'性别':<8} {'班级':<15} {'房间':<20} {'状态':<10} {'入住日期':<12}"
    print(header)
    print("-" * 120)
    
    for student in students:
        room_name = student.get('room_id')[1] if student.get('room_id') else "未分配"
        
        gender_map = {'male': '男', 'female': '女', 'other': '其他'}
        gender = gender_map.get(student.get('gender', ''), student.get('gender', ''))
        
        status_map = {
            'draft': '草稿', 'reservation': '预订', 'pending': '待定',
            'paid': '已付款', 'discharge': '已退房', 'cancel': '已取消'
        }
        status = status_map.get(student.get('status', ''), student.get('status', ''))
        
        check_in_date = student.get('check_in_date', '') or ''
        
        row = (
            f"{student.get('id', ''):<6} "
            f"{student.get('name', ''):<15} "
            f"{gender:<8} "
            f"{student.get('class_id', ''):<15} "
            f"{room_name:<20} "
            f"{status:<10} "
            f"{check_in_date:<12}"
        )
        print(row)
    
    print("=" * 120)


def print_student_details(students, limit=5):
    """打印学生详细信息"""
    print(f"\n\n详细信息（前 {min(limit, len(students))} 条）：")
    print("=" * 80)
    
    for i, student in enumerate(students[:limit], 1):
        print(f"\n【学生 {i}】")
        print(f"  ID: {student.get('id')}")
        print(f"  姓名: {student.get('name')}")
        print(f"  性别: {student.get('gender')}")
        print(f"  班级: {student.get('class_id')}")
        
        room_info = student.get('room_id')
        print(f"  房间: {room_info[1] if room_info else '未分配'}")
        
        hostel_info = student.get('hostel_id')
        print(f"  宿舍: {hostel_info[1] if hostel_info else '未分配'}")
        
        print(f"  入住日期: {student.get('check_in_date', '未设置')}")
        print(f"  退房日期: {student.get('check_out_date', '未设置')}")
        print(f"  住宿天数: {student.get('stay_duration', 0)} 天")
        print(f"  状态: {student.get('status')}")
        print(f"  是否激活: {'是' if student.get('active') else '否'}")
        print("-" * 80)
    
    if len(students) > limit:
        print(f"\n（共 {len(students)} 条记录，只显示前 {limit} 条详细信息）")


def main():
    """主函数"""
    print("=" * 80)
    print("Odoo JSON-RPC Client - 读取宿舍学生数据")
    print("=" * 80)
    print(f"服务器: {ODOO_URL}")
    print("=" * 80)
    
    # 1. 获取数据库列表
    databases = list_databases()
    print(f"\n可用的数据库: {databases}")
    
    # 2. 尝试每个数据库
    success_db = None
    uid = None
    
    for db in databases:
        print(f"\n尝试数据库: {db}")
        print(f"  正在验证...")
        
        uid, error = authenticate(db)
        
        if uid:
            print(f"  ✓ 验证成功！用户 ID: {uid}")
            success_db = db
            break
        else:
            print(f"  ✗ 验证失败")
    
    if not success_db:
        print("\n✗ 错误: 所有数据库验证失败")
        print("\n提示：请确认：")
        print("1. 数据库名称是否正确")
        print("2. API Key 是否有效")
        print("3. 服务器是否可访问")
        print(f"\n您可以手动指定数据库名称：")
        print(f"  python3 {sys.argv[0]} <database_name>")
        return
    
    print(f"\n使用数据库: {success_db}")
    print("=" * 80)
    
    try:
        # 3. 读取学生数据
        print("\n正在读取学生数据...")
        students, error = search_read_students(success_db, uid, API_KEY)
        
        if error:
            print(f"\n✗ 读取数据失败: {error}")
            return
        
        if not students:
            print("\n没有找到任何学生记录。")
            return
        
        # 4. 打印数据
        print_students(students)
        print_student_details(students, limit=5)
        
        print("\n✓ 数据读取完成！")
        print(f"\n数据库: {success_db}")
        print(f"总记录数: {len(students)}")
        
    except Exception as e:
        print(f"\n✗ 错误: {str(e)}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    # 支持命令行参数指定数据库名
    if len(sys.argv) > 1:
        COMMON_DB_NAMES = [sys.argv[1]]
    
    main()

